using System.Text;
using HotChocolate.Types.Analyzers.Helpers;

namespace HotChocolate.Types.Analyzers.FileBuilders;

public sealed class DataLoaderModuleFileBuilder : IDisposable
{
    private readonly string _moduleName;
    private StringBuilder _sb;
    private CodeWriter _writer;
    private bool _disposed;

    public DataLoaderModuleFileBuilder(string moduleName)
    {
        _moduleName = moduleName;
        _sb = PooledObjects.GetStringBuilder();
        _writer = new CodeWriter(_sb);
    }

    public void WriteHeader()
    {
        _writer.WriteIndentedLine("// <auto-generated/>");
        _writer.WriteLine();
        _writer.WriteIndentedLine("#nullable enable");
        _writer.WriteIndentedLine("#pragma warning disable");
        _writer.WriteLine();
        _writer.WriteIndentedLine("using System;");
        _writer.WriteIndentedLine("using System.Runtime.CompilerServices;");
        _writer.WriteIndentedLine("using GreenDonut;");
        _writer.WriteLine();
    }

    public void WriteBeginNamespace()
    {
        _writer.WriteIndentedLine("namespace Microsoft.Extensions.DependencyInjection");
        _writer.WriteIndentedLine("{");
        _writer.IncreaseIndent();
    }

    public void WriteEndNamespace()
    {
        _writer.DecreaseIndent();
        _writer.WriteIndentedLine("}");
    }

    public void WriteBeginClass(bool isInternal)
    {
        _writer.WriteIndentedLine(
            "{0} static partial class {1}DataLoaderServiceExtensions",
            isInternal ? "internal" : "public",
            _moduleName);
        _writer.WriteIndentedLine("{");
        _writer.IncreaseIndent();
    }

    public void WriteEndClass()
    {
        _writer.DecreaseIndent();
        _writer.WriteIndentedLine("}");
    }

    public void WriteBeginRegistrationMethod()
    {
        _writer.WriteIndentedLine(
            "public static IServiceCollection Add{0}(this global::{1} services)",
            _moduleName,
            WellKnownTypes.ServiceCollection);
        _writer.WriteIndentedLine("{");
        _writer.IncreaseIndent();
    }

    public void WriteEndRegistrationMethod()
    {
        _writer.WriteIndentedLine("return services;");
        _writer.DecreaseIndent();
        _writer.WriteIndentedLine("}");
    }

    public void WriteAddDataLoader(string dataLoaderType)
    {
        _writer.WriteIndentedLine(
            "global::{0}.AddDataLoader<global::{1}>(services);",
            WellKnownTypes.DataLoaderServiceCollectionExtension,
            dataLoaderType);
    }

    public void WriteAddDataLoader(
        string dataLoaderType,
        string dataLoaderInterfaceType,
        bool withInterface)
    {
        if (withInterface)
        {
            _writer.WriteIndentedLine(
                "global::{0}.AddDataLoader<global::{1}, global::{2}>(services);",
                WellKnownTypes.DataLoaderServiceCollectionExtension,
                dataLoaderInterfaceType,
                dataLoaderType);
        }
        else
        {
            _writer.WriteIndentedLine(
                "global::{0}.AddDataLoader<global::{1}>(services);",
                WellKnownTypes.DataLoaderServiceCollectionExtension,
                dataLoaderType);
        }
    }

    public void WriteAddDataLoaderGroup(string groupType, string groupInterfaceType)
    {
        _writer.WriteIndentedLine(
            "services.AddScoped<global::{0}, global::{1}>();",
            groupInterfaceType,
            groupType);
    }

    public override string ToString()
        => _sb.ToString();

    public void Dispose()
    {
        if (_disposed)
        {
            return;
        }

        PooledObjects.Return(_sb);
        _sb = null!;
        _writer = null!;
        _disposed = true;
    }
}
